const PENDING = 'pending';
const RESOLVED = 'resolved';
const REJECTED = 'rejected';

class Promise {
    constructor(executor) {
        this.status = PENDING; // 给promise对象指定status属性，初始值为pending
        this.data = undefined; //给promise对象指定一个用于存储结果数据的属性
        this.callbacks = []; // 每个元素的结构：onResolved(){}, onRejected(){}}
        const self = this;
        /**
         * status只能修改一次
         * 修改状态为resolved
         * 保存value数据
         * 如果有待执行的 callback函数，异步执行回调*/
        function resolve(value){
            if(self.status !== PENDING){
                return;
            }
            self.status = RESOLVED;
            self.data = value;
            if(self.callbacks.length > 0){
                setTimeout(()=>{
                    self.callbacks.forEach(callbacksObj=>{
                        callbacksObj.onResolved(value);
                    })
                })
            }
        }

        function reject(reason){
            if(self.status !== PENDING){
                return;
            }
            self.status = REJECTED;
            self.data = reason;
            if(self.callbacks.length > 0){
                setTimeout(()=>{
                    self.callbacks.forEach(callbacksObj=>{
                        callbacksObj.onRejected(reason);
                    })
                })
            }
        }
        /**
         * 立即同步执行executor
         * 如果抛出异常，则执行reject
         * */
        try{
            executor(resolve, reject);
        }catch (error){
            reject(error);
        }
    }
    /**
     * Promise原型对象的then（）
     * 指定成功和失败的回调函数
     * 返回一个新的promise对象
     * 返回的promise的结果由onResolved/onRejected执行结果决定
     * */
    then(onResolved,onRejected){
        /**
         * 指定默认的成功回调
         */
        onResolved = typeof onResolved === 'function'? onResolved: value => value;
        /**
         * 指定默认的失败回调（实现错误/异常穿透)
         * */
        onRejected = typeof onRejected === 'function' ?onRejected: reason => { throw reason}
        const self = this

        /**
         * 返回一个新的promise对象
         * */
        return new Promise((resolve, reject)=>{
            /**
             * 调用指定回调函数处理，根据执行结果，改变return的promise状态
             * */
            function handle(callback){
                /**
                 * 1.如果抛出异常，return的promise失败，reason就是error
                 * 2.如果回调函数执行返回非promise，return的promise就是value
                 * 3.如果回调函数返回是promise，return的promise结果就是这个promise结果
                 * */
                try{
                    const result = callback(self.data);
                    // 情况3
                    if(result instanceof Promise){
                        // result.then(
                        //     value=>resolve(value), // result成功，返回
                        //     reason => reject(reason)// result失败。返回
                        // )
                        //这是上面的简写
                        result.then(resolve, reject);
                    }else { // 情况2
                        resolve(result);
                    }
                }catch(error){ // 情况1
                    reject(error)
                }
            }
            if(self.status === PENDING){
                //当前还是pending状态，保存回调函数
                self.callbacks.push({
                    onResolved(){
                        handle(onResolved)
                    },
                    onRejected(){
                        handle(onRejected);
                    }
                })
                // 当前是resolved状态，异步执行onResolved
            }else if(self.status === RESOLVED){
                setTimeout(()=>{
                    handle(onResolved)
                })
            }else {
                //当前是reject状态
                setTimeout(()=>{
                    handle(onRejected);
                })
            }

        })
    }
    /**
     * Promise原型对象的catch
     * 指定失败的回调函数
     * 返回一个新的promise对象*/
    catch(onRejected){
        return this.then(undefined, onRejected);
    }
    /**
     * Promise函数对象的resolve方法
     * 返回一个指定value的成功的promise
     * */
    static resolve(value){
        return new Promise((resolve,reject)=>{
            if(value instanceof Promise){
                value.then(resolve,reject);
            }else {
                resolve(value);
            }
        })
    }
    /**
     * Promise函数对象的reject方法
     * 返回一个指定reason的失败的promise
     * */
    static reject(reason){
        return new Promise((resolve,reject)=>{
            reject(reason);
        })
    }

    /**
     * Promise函数对象的all方法
     * 返回一个的promise，只有当所有promise都成功时才成功，否则只要有一个失败就失败
     * */
    static all(promises){
        return new Promise((resolve, reject)=>{
            let values = [];
            let promiseCount = 0;
            // 遍历promise获取每个promise的结果
            promises.forEach((p,index)=>{
                Promise.resolve(p).then(value=>{
                    values[index] = value;
                    promiseCount++;
                    if(promiseCount === promises.length){
                        resolve(values);
                    }
                }, reason => {
                    reject(reason);
                })
            })
        })
    }
    /**
     * Promise函数对象的race方法
     * 返回一个的promise，其结果由第一个完成的promise决定
     * */
    static race = function (promise){
        return new Promise((resolve, reject)=>{
            promise.forEach(p=>{
                Promise.resolve(p).then(resolve, reject)
                // p.then(value=>{
                //     resolve(value);
                // },reason=>{
                //     reject(reason);
                // })
            })
        })
    }
    /**
     * 返回一个promise对象，在指定的时间后才确定结果
     * */
    static resolveDelay (value, time){
        return new Promise((resolve,reject)=>{
            setTimeout(()=>{
                if(value instanceof Promise){
                    value.then(resolve,reject);
                }else {
                    resolve(value);
                }
            }, time);
        })

    }

    static rejectDelay(reason, time){
        return new Promise((resolve,reject)=>{
            setTimeout(()=>{
                reject(reason);
            }, time);
        })


    }
}